<!DOCTYPE html>
<html>
<head>
    <title>Thermodynamics Diagram</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas id="thermoCanvas" width="550" height="420"></canvas>
    <script>
        const canvas = document.getElementById('thermoCanvas');
        const ctx = canvas.getContext('2d');

        // --- Helper Functions ---

        /**
         * Draws text with a subscript.
         * @param {CanvasRenderingContext2D} ctx The canvas context.
         * @param {string} text The main text.
         * @param {string} sub The subscript text.
         * @param {number} x The x-coordinate for the start of the main text.
         * @param {number} y The y-coordinate for the baseline of the main text.
         */
        function drawSubscriptText(ctx, text, sub, x, y) {
            const originalFont = ctx.font;
            const originalBaseline = ctx.textBaseline;

            // Main text
            ctx.font = 'italic 24px Times New Roman';
            ctx.textBaseline = 'bottom';
            ctx.fillText(text, x, y);
            const textWidth = ctx.measureText(text).width;

            // Subscript text
            ctx.font = 'italic 16px Times New Roman';
            ctx.fillText(sub, x + textWidth * 0.9, y + 4);

            // Restore original settings
            ctx.font = originalFont;
            ctx.textBaseline = originalBaseline;
        }

        /**
         * Draws a straight line with an arrowhead at the end.
         * @param {CanvasRenderingContext2D} ctx The canvas context.
         * @param {number} fromX The starting x-coordinate.
         * @param {number} fromY The starting y-coordinate.
         * @param {number} toX The ending x-coordinate.
         * @param {number} toY The ending y-coordinate.
         * @param {number} headLength The length of the arrowhead sides.
         */
        function drawArrow(ctx, fromX, fromY, toX, toY, headLength = 10) {
            const dx = toX - fromX;
            const dy = toY - fromY;
            const angle = Math.atan2(dy, dx);

            ctx.beginPath();
            ctx.moveTo(fromX, fromY);
            ctx.lineTo(toX, toY);

            // Arrowhead
            ctx.moveTo(toX, toY);
            ctx.lineTo(toX - headLength * Math.cos(angle - Math.PI / 6), toY - headLength * Math.sin(angle - Math.PI / 6));
            ctx.moveTo(toX, toY);
            ctx.lineTo(toX - headLength * Math.cos(angle + Math.PI / 6), toY - headLength * Math.sin(angle + Math.PI / 6));
            ctx.stroke();
        }
        
        /**
         * Draws a cloud symbol (a simple arc).
         * @param {CanvasRenderingContext2D} ctx The canvas context.
         * @param {number} x The center x-coordinate of the arc.
         * @param {number} y The center y-coordinate of the arc.
         * @param {number} radius The radius of the arc.
         */
        function drawCloudSymbol(ctx, x, y, radius = 9) {
            ctx.beginPath();
            ctx.arc(x, y, radius, Math.PI * 1.15, Math.PI * 1.85, true);
            ctx.stroke();
        }

        // --- Main Drawing Logic ---

        // Global style settings
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';
        ctx.lineWidth = 2;

        const y_base = 320;

        // 1. Draw the mountain profile
        const m0_start_x = 100;
        const m1_x = 170, m1_y = 240;
        const m2_x = 280, m2_y = 120;
        const m3_end_x = 450;
        ctx.beginPath();
        ctx.moveTo(m0_start_x, y_base);
        ctx.bezierCurveTo(120, 320, 140, 270, m1_x, m1_y); // Slope to M1
        ctx.bezierCurveTo(190, 190, 240, 120, m2_x, m2_y); // Slope from M1 to M2
        ctx.bezierCurveTo(350, 150, 420, 320, m3_end_x, y_base); // Slope from M2 to M3
        ctx.stroke();

        // 2. Draw the base line
        ctx.beginPath();
        ctx.moveTo(50, y_base);
        ctx.lineTo(500, y_base);
        ctx.stroke();

        // 3. Draw the labels M0, M1, M2, M3
        drawSubscriptText(ctx, 'M', '0', 70, y_base + 30);
        drawSubscriptText(ctx, 'M', '1', 140, m1_y + 25);
        drawSubscriptText(ctx, 'M', '2', m2_x - 10, m2_y - 15);
        drawSubscriptText(ctx, 'M', '3', 460, y_base + 30);

        // 4. Draw h1 dimension and related elements
        const h1_level_y = m1_y;
        const h1_base_y = 300;
        const h1_dim_x = 220;

        // Dashed lines for height visualization
        ctx.save();
        ctx.setLineDash([5, 4]);
        ctx.beginPath();
        ctx.moveTo(140, h1_level_y); // M1 level line
        ctx.lineTo(h1_dim_x + 10, h1_level_y);
        ctx.moveTo(140, h1_base_y); // Base level line
        ctx.lineTo(h1_dim_x + 10, h1_base_y);
        ctx.stroke();
        ctx.restore();

        // h1 dimension arrow
        drawArrow(ctx, h1_dim_x, h1_base_y, h1_dim_x, h1_level_y);
        // h1 label
        drawSubscriptText(ctx, 'h', '1', 185, (h1_base_y + h1_level_y) / 2 + 10);

        // 5. Draw precipitation arrow (the downward arrow above M1 level)
        drawArrow(ctx, 200, h1_level_y - 30, 200, h1_level_y);

        // 6. Draw airflow arrows
        ctx.save();
        ctx.lineWidth = 2.5;

        // Upward flow (curved arrow)
        const p0 = { x: 130, y: 295 };
        const p1 = { x: 150, y: 255 }; // Control point
        const p2 = { x: 180, y: 215 }; // End point
        ctx.beginPath();
        ctx.moveTo(p0.x, p0.y);
        ctx.quadraticCurveTo(p1.x, p1.y, p2.x, p2.y);
        ctx.stroke();
        // Arrowhead for the curved arrow
        const angle_up = Math.atan2(p2.y - p1.y, p2.x - p1.x); // Angle at the end of the curve
        const headlen = 12;
        ctx.beginPath();
        ctx.moveTo(p2.x, p2.y);
        ctx.lineTo(p2.x - headlen * Math.cos(angle_up - Math.PI / 6), p2.y - headlen * Math.sin(angle_up - Math.PI / 6));
        ctx.moveTo(p2.x, p2.y);
        ctx.lineTo(p2.x - headlen * Math.cos(angle_up + Math.PI / 6), p2.y - headlen * Math.sin(angle_up + Math.PI / 6));
        ctx.stroke();

        // Downward flow (straight arrow)
        drawArrow(ctx, m2_x + 40, m2_y + 40, m2_x + 90, m2_y + 110);
        ctx.restore();

        // 7. Draw clouds
        drawCloudSymbol(ctx, 160, 195);
        drawCloudSymbol(ctx, 180, 200);
        drawCloudSymbol(ctx, 200, 190);
        drawCloudSymbol(ctx, 175, 180);
        drawCloudSymbol(ctx, 195, 175);
        drawCloudSymbol(ctx, 215, 170);
        drawCloudSymbol(ctx, 185, 165);

        // 8. Draw Caption
        ctx.textAlign = 'center';
        ctx.font = '24px "KaiTi", "SimSun"'; // Standard Chinese fonts
        ctx.fillText('热图 2.14.1', 275, 380);

    </script>
</body>
</html>